#include "timer.h"
#include "jobqueue.h"

TimerThread G_TIMER_THREAD;

TimerThread::TimerThread() 
  :next_id_(0), running_(false) { 
  SetTimes(); 
}

void InitTimer() {
  static bool done = false;
  if (done) return;
  done = true;
  if (ConfigString("timer_thread") == "true") 
    G_TIMER_THREAD.Launch();
}

void * RunTimerThread(void * t) {
  TimerThread * tt = (TimerThread *) t;
  tt->Run();
  return NULL;
}

void TimerThread::SetTimes() {
  int64 new_time = TimeNS();
  if (new_time == time_[0]) return;
  if (new_time > time_[0] && new_time < time_[0] + 10000) return;
  for (int64 i=0; i<kTimerNumSpots; i++) 
    time_[i * kTimerSpacing] = new_time;
}

void TimerThread::Launch() {
  cout << "TimerThread::Launch" << endl;
  running_ = true; 
  SetTimes();
  pthread_t * thread = new pthread_t;
  pthread_create(thread, NULL, RunTimerThread, this);
}


struct TimeTask : public JobQueue::Task {
  TimeTask(int which) {
    which_ = which;
  }
  void Run() {
    uint64 n = 1000000ull;
    uint64 start_time = G_TIMER_THREAD.Get(which_);
    uint64 old_time = start_time;
    uint64 num_different = 0;
    for (uint64 i=0; i<n; i++) {
      uint64 new_time = G_TIMER_THREAD.Get(which_);
      if (new_time != old_time) {
	num_different++;
	old_time = new_time;
      }      
    }
    uint64 end_time = G_TIMER_THREAD.Get(which_);
    cout << "Average timer time (NS) " << ((end_time - start_time) / (double)n) << endl;
    cout << "Average non-zero time difference (NS) " << ((end_time - start_time) / num_different) << endl;
  }
  int which_;
};


void TimeTest() {
  /* for (uint64 i=0; i<1000; i++) { 
    timespec ts;
    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
    cout << ts.tv_sec << " " << ts.tv_nsec << endl;
  }
  return; */

  G_TIMER_THREAD.Launch();
  JobQueue::Job j(G_JQ);
  for (uint64 i=0; i<24; i++) {
    j.AddTask(new TimeTask(G_TIMER_THREAD.GetID()));
  }
  j.Wait();
}

